#include "RTC.h"

date_time_t date_time = {0};
// RTC配置
void RTC_Config(void)
{
    rcu_periph_clock_enable(RCU_BKPI); // 使能备份域时钟
    rcu_periph_clock_enable(RCU_PMU);  // 使能电源管理时钟
    pmu_backup_write_enable();         // 备份域访问允许
    bkp_deinit();                      // 备份域复位

    rcu_osci_on(RCU_LXTAL);                 // 使能外部低速时钟
    rcu_osci_stab_wait(RCU_LXTAL);          // 等待外部低速时钟稳定
    rcu_rtc_clock_config(RCU_RTCSRC_LXTAL); // 选择时钟源

    rcu_periph_clock_enable(RCU_RTC);     // 使能RTC时钟
    rtc_register_sync_wait();             // 等待寄存器和APB1时钟同步
    rtc_lwoff_wait();                     // 等待RTC的最后一次操作完成
    rtc_interrupt_enable(RTC_INT_SECOND); // 使能RTC秒中断
    rtc_lwoff_wait();                     // 等待RTC的最后一次操作完成

    rtc_prescaler_set(32767); // 设置预分频寄存器
    rtc_lwoff_wait();         // 等待RTC的最后一次操作完成
}
// RTC中断配置
void RTC_NVIC_Config(void)
{
    nvic_irq_enable(RTC_IRQn, 2, 0);
}
// RTC初始化
uint8_t RTC_Init(void)
{
    RTC_Config();
    RTC_Set(2024, 12, 31, 16, 34, 0);
    RTC_NVIC_Config();
    return 0;
}
// RTC中断服务函数
void RTC_IRQHandler(void)
{
    if (rtc_flag_get(RTC_FLAG_SECOND))//判断是否为秒中断
    {
        rtc_flag_clear(RTC_FLAG_SECOND);
        RTC_Get();
        printf("date-time is %d-%d-%d %d-%d-%d!!!\r\n", date_time.year, date_time.month, date_time.day, date_time.hour, date_time.minute, date_time.second);
    }
}

int is_leap_year(int year)
{
    if (year % 4 == 0)
    {
        if (year % 100 == 0)
        {
            if (year % 400 == 0)
                return 1;
            else
                return 0;
        }
        else
        {
            return 1;
        }
    }
    else
    {
        return 0;
    }
}

int days_from_1970(int year, int month, int day)
{
    int days = 0;
    int y;

    for (y = 1970; y < year; y++)
    {
        days += is_leap_year(y) ? 366 : 365;
    }

    int months_days[] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
    if (is_leap_year(year))
    {
        months_days[1] = 29;
    }

    for (int m = 0; m < month - 1; m++)
    {
        days += months_days[m];
    }

    days += (day - 1); // since 1970-01-01 is day 0

    return days;
}

void seconds_to_datetime(uint32_t epoch_seconds, uint16_t *year, uint8_t *month, uint8_t *day, uint8_t *hour, uint8_t *minute, uint8_t *second)
{
    const int SECS_PER_MIN = 60;
    // const int SECS_PER_HOUR = 3600;
    // const int SECS_PER_DAY = 86400;

    unsigned int secs = epoch_seconds;

    *second = secs % SECS_PER_MIN;
    secs /= SECS_PER_MIN; // mins since 1970-01-01

    *minute = secs % SECS_PER_MIN;
    secs /= SECS_PER_MIN; // hours since 1970-01-01

    *hour = secs % 24;
    secs /= 24; // days since 1970-01-01

    // Now secs is the number of days since 1970-01-01
    int days = secs;

    int y = 1970;
    int m = 1;
    int d = 1;

    while (days >= 365)
    {
        if (is_leap_year(y) && days >= 366)
        {
            days -= 366;
            y++;
        }
        else if(is_leap_year(y) && days == 365)
        {
            break;
        }
        else
        {
            days -= 365;
            y++;
        }
    }

    int months_days[] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
    if (is_leap_year(y))
    {
        months_days[1] = 29;
    }

    for (m = 1; m <= 12; m++)
    {
        if (days < months_days[m - 1])
        {
            break;
        }
        days -= months_days[m - 1];
    }

    d = days + 1;

    *year = y;
    *month = m;
    *day = d;
}
// 将设置时间转化为秒数，给到RTC_CNT寄存器
uint8_t RTC_Set(uint16_t year, uint8_t month, uint8_t day, uint8_t hour, uint8_t minute, uint8_t second)
{
    int32_t tmp_days = 0;
    uint32_t tmp_sec = 0;
    tmp_days = days_from_1970(year,month,day);
    tmp_sec = tmp_days * (24*60*60);
    tmp_sec = tmp_sec + (hour * 60 * 60);
    tmp_sec = tmp_sec + (minute * 60);
    tmp_sec = tmp_sec + second;
    rtc_lwoff_wait();         // 等待RTC的最后一次操作完成
    rtc_counter_set(tmp_sec);
    return 0;
}
// 获取RTC_CNT寄存器的秒数，并转化为日期
uint8_t RTC_Get(void)
{
    uint32_t tmp_sec = 0;
    tmp_sec = rtc_counter_get();
    seconds_to_datetime(tmp_sec,&date_time.year,&date_time.month,&date_time.day,&date_time.hour,&date_time.minute,&date_time.second);
    return 0;
}
